<?php
/**
 * Created by PhpStorm
 * User: whh
 * Date: 2022/12/13
 * Time: 11:12
 */

namespace app\common\server;

use app\common\command\NiuNiuTui;
use app\common\coroutinePool\MysqlPoolCoroutine;
use Swoole\Server;
use Swoole\Coroutine;
use think\facade\Env;

class TcpServer
{
    private $server;
    private $host;
    private $port;
    private $config;
    private $pool = null;

    public function __construct(array $config, $host, int $port)
    {
        $this->config = $config;
        $this->host = $host;
        $this->port = $port;
    }

    public function run()
    {
        $this->pool = MysqlPoolCoroutine::getInstance();//连接池对象
        $this->server = new Server($this->host, $this->port);
        $this->server->set($this->config);
        $this->server->on('WorkerStart', [$this, 'onWorkerStart']);
        $this->server->on('receive', [$this, 'onReceive']);
        $this->server->on('task', [$this, 'onTask']);
        $this->server->on('finish', [$this, 'onFinish']);
        /**
         * dispatch_mode=1/3 时，底层会屏蔽 onConnect/onClose 事件，原因是这 2 种模式下无法保证 onConnect/onClose/onReceive 的顺序；
         * $this->server->on('connect', [$this, 'onConnect']);
         * $this->server->on('close', [$this, 'onClose']);
         */
        $this->server->start();
    }


    /**
     * 接收到数据时回调此函数
     * @param $server
     * @param $fd
     * @param $reactor_id
     * @param $data
     * @Author: whh
     */
    function onReceive($server, $fd, $reactor_id, $data)
    {
        $receiveData = json_decode($data, true);
        if (isset($receiveData['cmd'])) {
            switch ($receiveData['cmd']) {
                case '_reload':
                    $this->server->reload();
                    $responseData['msg'] = '系统正在重启中';
                    $responseData['sys_info'] = $server->stats();
                    $this->server->send($fd, $this->jsonFormat($responseData));
                    break;
                case '_shutdown':
                    $responseData['msg'] = '系统正在关闭';
                    $responseData['sys_info'] = $server->stats();
                    $this->server->send($fd, $this->jsonFormat($responseData));
                    $this->server->shutdown();
                    break;
                case '_nnt':
                    $this->server->task($receiveData);
                    $responseData['msg'] = "offset:{$receiveData['offset']} length:{$receiveData['length']} 采集任务已投递";
                    $this->server->send($fd, $this->jsonFormat($responseData));
                    break;
                case '_custom':
                    break;
                default:
                    $this->server->send($fd, '未知命令：' . $data . PHP_EOL);
                    break;
            }
        } else {
            $this->server->send($fd, 'server onReceive' . PHP_EOL);
        }
    }

    function onWorkerStart(Server $server, int $workerId)
    {

    }

    function onTask(Server $server, $task)
    {
        if ($task->data['cmd'] == "_nnt") {
            $nnt = new NiuNiuTui();
            $pdo = $this->pool->get();
            $nnt->collectNovel($pdo, $task->data['offset'], $task->data['length']);
            $this->pool->put($pdo);
        }
        $task->finish([$task->worker_id, $task->id]); //完成任务，结束并返回数据
    }


    function onFinish(Server $server, int $task_id, $data)
    {

    }

    function onConnect(Server $server, int $fd, int $reactorId)
    {
        echo "onConnect：" . $reactorId . PHP_EOL;
    }

    function onClose(Server $server, int $fd, int $reactorId)
    {
        echo "onClose：" . $reactorId . PHP_EOL;
    }


    /**
     * 格式化json用户服务器输出
     * @param $data
     * @param null $indent
     * @return string
     * @Author: whh
     */
    private function jsonFormat($data, $indent = null)
    {
        // json encode
        $data = json_encode($data, JSON_UNESCAPED_UNICODE);

        // 将urlencode的内容进行urldecode
        $data = urldecode($data);

        // 缩进处理
        $ret = '';
        $pos = 0;
        $length = strlen($data);
        $indent = isset($indent) ? $indent : '    ';
        $newline = PHP_EOL;
        $prevchar = '';
        $outofquotes = true;

        for ($i = 0; $i <= $length; $i++) {

            $char = substr($data, $i, 1);

            if ($char == '"' && $prevchar != '\\') {
                $outofquotes = !$outofquotes;
            } elseif (($char == '}' || $char == ']') && $outofquotes) {
                $ret .= $newline;
                $pos--;
                for ($j = 0; $j < $pos; $j++) {
                    $ret .= $indent;
                }
            }

            $ret .= $char;

            if (($char == ',' || $char == '{' || $char == '[') && $outofquotes) {
                $ret .= $newline;
                if ($char == '{' || $char == '[') {
                    $pos++;
                }

                for ($j = 0; $j < $pos; $j++) {
                    $ret .= $indent;
                }
            }

            $prevchar = $char;
        }

        return $ret;
    }
}